<!--
*- coding = utf-8 -*-
#@Time : 2023-06-29 23:59
#@Author : 管茂良
#@File : virtualList.vue
#@web  : www.php-china.com
#@Software: WebStorm
-->
<template>
    <div>
        <div class="listContainer" :style="{height:props.containerHeight,width:'100%'}" @scroll="handleScroll">
            <div class="listContainerPhantom" :style="{ height: listHeight + 'px' }"></div>
            <div class="listContainerList" :style="{ transform: computedTransform }">
                <div class="list" style="width:auto;height:auto" v-bind="attrs">
                    <div ref="listItemRef"  :key="index+'-'+item?.id" v-for="(item,index) in computedVisibleData">
                        <slot :data="item"></slot>
                    </div>
                </div>
            </div>
        </div>
    </div>
</template>

<script setup lang="ts">
    import {computed, onMounted, ref, watch,useAttrs,nextTick} from "vue";

    let startNum = ref(0)
    let endNum = ref(0)

    let startOffset = ref(0);//偏移量
    let listHeight = ref(0);//列表总高度
    let listItemHeight = ref(0);//每项高度
    let listItemWidth = ref(0);//每项宽度
    let listItemRef = ref(null);

    let attrs = useAttrs()

    interface propsInterface{
        data?:any              //列表数据
        containerHeight?:string   //容器高度
    }
    let props = withDefaults(defineProps<propsInterface>(),{
        //所有数据
        data:[],
        containerHeight:"",
    })

    const computedTransform = computed(()=>{
        return `translate3d(0,${startOffset.value}px,0)`;
    })
    //可看得见的数据
    const computedVisibleData = computed(()=>{
        return props.data.slice(startNum.value,Math.min(endNum.value,props.data.length))
    })

    const handleScroll = ()=>{
        let listContainer:any = document.querySelector(".listContainer");//列表容器
        //可显示的数量
        let listContainerHeight = listContainer?.offsetHeight
        let listContainerWidth = listContainer?.offsetWidth
        let colsNum = Math.ceil(listContainerWidth / listItemWidth.value)
        let rowsNum = Math.ceil(listContainerHeight / listItemHeight.value)
        let showNum = colsNum*rowsNum

        //滚动高度
        let contentScrollTop = Math.floor(listContainer.scrollTop);
        let curNum = Math.ceil((contentScrollTop / listItemHeight.value)*colsNum);
        if(startNum.value!=curNum){
            startNum.value = curNum
            endNum.value = showNum + startNum.value
            //滚动高度减去空隙
            startOffset.value = contentScrollTop - (contentScrollTop%listItemHeight.value)
        }
    }

    const handleInit = ()=>{
        nextTick(()=>{
            let listContainer:any = document.querySelector(".listContainer");//列表容器
            let contentScrollTop = Math.floor(listContainer.scrollTop);
            if(contentScrollTop>0){
                return;
            }
            let listItem:any = listItemRef.value ;//每一列
            let listContainerHeight = listContainer?.offsetHeight
            let listContainerWidth = listContainer?.offsetWidth
            //每项高度获取为1，所以导致bug出现
            listItemHeight.value = listItem ? listItem[0]?.offsetHeight : 1
            listItemWidth.value = listItem ? listItem[0]?.offsetWidth : 1

            let colsNum = Math.ceil(listContainerWidth / listItemWidth.value)
            let rowsNum = Math.ceil(listContainerHeight / listItemHeight.value)
            let showNum = colsNum*rowsNum
            //列表总高度
            listHeight.value = Math.ceil(props.data.length/colsNum)*listItemHeight.value
            endNum.value = startNum.value + showNum
        })
    }
    //监听列表高度，有变化，重新初始化
    watch(()=>[listItemRef.value],(value)=>{
        handleInit()
    },{immediate:true,deep:true})

    onMounted(()=>{
        startNum.value = 0
        handleInit()
    })
</script>

<style scoped lang="less">
    .listContainer{
        height:400px;
        overflow: auto;
        position: relative;
        -webkit-overflow-scrolling: touch;
        .listContainerPhantom{
            position: absolute;
            left: 0;
            top: 0;
            right: 0;
            z-index: -1;
        }
        .listContainerList{
            left: 0;
            right: 0;
            top: 0;
            position: absolute;
            text-align: center;
            padding:12px;
        }

    }
</style>
